package com.youdianda.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youdianda.constant.MessageConstant;
import com.youdianda.context.BaseContext;
import com.youdianda.dto.*;

import com.youdianda.entity.*;
import com.youdianda.exception.AccountLockedException;
import com.youdianda.exception.AccountNotFoundException;
import com.youdianda.exception.PasswordErrorException;
import com.youdianda.mapper.*;
import com.youdianda.result.PageResult;
import com.youdianda.result.Result;
import com.youdianda.service.IYddUserService;
import com.youdianda.untils.JwtUtil;
import com.youdianda.vo.UserDataVo;

import com.youdianda.vo.UserInfoVo;
import com.youdianda.vo.YddUserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author mosen
 * @since 2023-05-15
 */
@Service
public class YddUserServiceImpl extends ServiceImpl<YddUserMapper, YddUser> implements IYddUserService {
    @Autowired
    private YddUserMapper yddUserMapper;

    @Autowired
    private YddArticleMapper yddArticleMapper;

    @Autowired
    private YddUserDataMapper yddUserDataMapper;

    @Autowired
    private SysDictMapper sysDictMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;


    /**
     * 登录
     *
     * @param dto
     * @return
     */
    @Override
    public Result login(UserLoginDTO dto) {
        if(dto.getLoginName().isEmpty()){
            return Result.error("请输入正确的用户名");
        }
        if(dto.getPassword().isEmpty()){
            return Result.error("请输入正确的密码");
        }
        QueryWrapper<SysUser> qw = new QueryWrapper<SysUser>();
        String password = DigestUtils.md5DigestAsHex(dto.getPassword().getBytes());
        qw.eq("login_name",dto.getLoginName());
        qw.eq("password",password);
        SysUser sysUser = sysUserMapper.selectOne(qw);
        if(sysUser==null){
            return Result.error("请输入正确的用户名和密码");
        }
        String token = JwtUtil.getToken(sysUser.getId());
        Map map = new HashMap();
        map.put("token",token);
        return Result.success(map);
    }

    /**
     * 获取用户资料
     *
     * @return
     */
    @Override
    public Result getUserData() {
        String id = BaseContext.getCurrentId();
        //获取对应用户
        SysUser sysUser = sysUserMapper.selectById(id);
        String str = sysUser.getRoleId();
        String[] split = str.substring(1, str.length() - 1).split(",");
        List<String> collects = Arrays.stream(split).map(s->s.replace("\"","")).collect(Collectors.toList());

        Set<String> rolemenuIds = new HashSet<>();
        //通过角色获取菜单
        collects.forEach(collect->{
            SysRole sysRole = sysRoleMapper.selectById(collect);
            QueryWrapper qw = new QueryWrapper();
            qw.eq("role_id",sysRole.getId());

            List<SysRoleMenu> list = sysRoleMenuMapper.selectList(qw);

            List<String> menuIds = list.stream().map(s -> s.getMenuId()).collect(Collectors.toList());
            rolemenuIds.addAll(menuIds);
        });

        LambdaQueryWrapper<SysMenu> lqw = new LambdaQueryWrapper();
        lqw.in(SysMenu::getId,rolemenuIds);
        lqw.eq(SysMenu::getType,1);
        //获取对应菜单对象
        List<SysMenu> menuList = sysMenuMapper.selectList(lqw);

        LambdaQueryWrapper<SysDict> lqw2 = new LambdaQueryWrapper();
        lqw2.select(SysDict::getType);
        lqw2.groupBy(SysDict::getType);
        List<SysDict> sysDicts = sysDictMapper.selectList(lqw2);

        Map DictsMap = new HashMap();
        sysDicts.forEach(s->{
            LambdaQueryWrapper<SysDict> lqw3 = new LambdaQueryWrapper();
            lqw3.select(SysDict::getValue, SysDict::getLabel);
            lqw3.eq(SysDict::getType,s.getType());
            List<SysDict> Dicts = sysDictMapper.selectList(lqw3);

            Map<String, String> collect = Dicts.stream().collect(Collectors.toMap(SysDict::getValue, SysDict::getLabel));
            DictsMap.put(s.getType(),collect);
        });
        Map map = new HashMap();
        map.put("userInfo",sysUser);
        map.put("menuList",menuList);
        map.put("dictsList",DictsMap);

        return Result.success(map);
    }

    /**
     * 获取用户信息
     * @return
     */
    @Override
    public Result<UserInfoVo> getUserDataFront() {
        //获取用户信息，并返回
        //设计三张表 ydd_user ydd_user_data(中间表) ydd_article
        //获取用户di
        Integer id = Integer.valueOf(BaseContext.getCurrentId());
        //查询用户信息
        QueryWrapper<YddUser> qw = new QueryWrapper<>();
        qw.eq("id",id);
        YddUser yddUser = yddUserMapper.selectOne(qw);

        //根据用户di查询文章数目
        QueryWrapper<YddArticle> qw1 = new QueryWrapper<>();
        qw1.eq("user_id",id);
        Long articleNum = yddArticleMapper.selectCount(qw1);

        //根据中间表获取文章收藏数、点赞数
        QueryWrapper<YddUserData> qw2 = new QueryWrapper<>();
        qw2.eq("user_id",id).eq("type",1);
        qw2.groupBy("type");
        Long collectNum = yddUserDataMapper.selectCount(qw2);
        qw2 = new QueryWrapper<YddUserData>();
        qw2.eq("user_id",id).eq("type",2);
        qw2.groupBy("type");
        Long zanNum = yddUserDataMapper.selectCount(qw2);

        //返回
        UserInfoVo vo = new UserInfoVo(articleNum,collectNum,yddUser,zanNum);
        return Result.success(vo);
    }


    /**
     * 获取我的文章信息
     * @param dto
     * @return
     */
    @Override
    public Result getMyArticle(MyArticleQueryDTO dto) {
        //非空判断limit、page是否为空，省略
        //利用mp的分页进行查询
        //1 创建IPage分页对象,设置分页参数
        Integer limit = dto.getLimit();
        Integer page = dto.getPage();
        IPage<YddArticle> iPage = new Page<>(page, limit);

        //2 执行分页查询
        //获取用户di
        Integer id = Integer.valueOf(BaseContext.getCurrentId());
        QueryWrapper<YddArticle> qw = new QueryWrapper<>();
        qw.eq("user_id",id);
        qw.orderByDesc("create_date");
        yddArticleMapper.selectPage(iPage, qw);

        //3 获取分页结果，进行封装
        List<YddArticle> data = iPage.getRecords();
        long count = iPage.getTotal();
        long totalPages = iPage.getPages();
        long currentPage = iPage.getCurrent();
        long pageSize = iPage.getSize();

        PageResult list = new PageResult(count, totalPages, pageSize, currentPage, data);

        return Result.success(list);

    }

    /**
     * 获取我的收藏/点赞文章
     * @param dto
     * @return
     */
    @Override
    public Result getUserDataList(UserDataListDTO dto) {
        //条件分页查询文章表，条件为type
        //设计的表ydd_user ydd_user_data(中间表) ydd_article

        //利用mp的分页进行查询
        //1 创建IPage分页对象,设置分页参数
        Integer limit = dto.getLimit();
        Integer page = dto.getPage();
        IPage<YddArticle> iPage = new Page<>(page, limit);

        //2 执行分页查询
        //获取用户id
        Integer id = Integer.valueOf(BaseContext.getCurrentId());
        //根据中间表获取文章收藏数集合id 或者|| 点赞数集合id
        QueryWrapper<YddUserData> qw = new QueryWrapper<>();
        qw.select("article_id").eq("user_id",id).eq("type",dto.getType());

        //条件查询得到对应的对象，然后封装对应的article_id到集合中
        List<YddUserData> yddUserDataList = yddUserDataMapper.selectList(qw);

        //！！！！没有点赞文章或者收藏需要处理
        if (yddUserDataList == null || yddUserDataList.size() == 0) {
            Map<Object, Object> map = new HashMap<>();
            map.put("list",null);
            return Result.success(map); //提前返回空
        }

        List<Integer> ids = new ArrayList<>();
        for (YddUserData yddUserData : yddUserDataList) {
            ids.add(yddUserData.getArticleId());
        }

        //根据查询得到的对应的id去分页查询文章表
        QueryWrapper<YddArticle> qw1 = new QueryWrapper<>();
        qw1.in("id",ids);
        yddArticleMapper.selectPage(iPage,qw1);

        //3 获取分页结果，进行封装
        List<YddArticle> data = iPage.getRecords();
        long count = iPage.getTotal();
        long totalPages = iPage.getPages();
        long currentPage = iPage.getCurrent();
        long pageSize = iPage.getSize();

        PageResult list = new PageResult(count, totalPages, pageSize, currentPage, data);
        Map<Object, Object> map = new HashMap<>();
        map.put("list",list);

        return Result.success(map);
    }

    /**
     * 修改用户资料，这里不需要先回显再查询，因为回显数据从/getUserInfo中获取
     * @param yddUser
     * @return
     */
    @Override
    public Result updateUser(YddUser yddUser) {
        //前台会传入id
        //检验id
        Integer id = yddUser.getId();
        if (id == null) {
            return Result.error("id为空，不能更改");
        }

        QueryWrapper<YddUser> qw = new QueryWrapper<>();
        qw.eq("id",id);

        yddUserMapper.update(yddUser,qw);
        return Result.success("修改成功！");
    }




    /**
     * 点赞/取消点赞和收藏/取消收藏
     * @param dto
     * @return
     */
    @Override
    public Result updateCollectOrZan(UpdateCollectOrZanDTO dto) {
        //分析
        //点赞修改只需要修改ydd_user_data表即可
        //收藏数量改变需要修改ydd_article表、ydd_user_data表
        //需要根据类型判断是为add(点赞||收藏) 还是 del(取消点赞||取消收藏)

        //获取用户id
        Integer id = Integer.valueOf(BaseContext.getCurrentId());
        //获取文章id
        Integer articleId = dto.getArticle_id();

        //先判断文章是否存在，不存在则返回错误
        YddArticle yddArticle = yddArticleMapper.selectById(articleId);
        if (yddArticle  == null) {
            return Result.error("文章不存在，不能更改收藏或点赞");
        }

        //判断type，1表示收藏操作，2表示点赞操作
        Integer type = dto.getType();
        //add表示 点赞或收藏， del表示取消点赞或取消收藏
        String action = dto.getAction();

        if (type == 1) { //收藏
            //根据articleId，获取lovenum
            //根据文章id修改字段lovenum收藏数量,先查询lovenum数量再进行修改
            Integer lovenum = Integer.valueOf(yddArticle.getLovenum());

            if ("add".equals(action)){ //添加
                //1-修改ydd_article表
                yddArticle.setLovenum(lovenum + 1 + "");
                yddArticleMapper.updateById(yddArticle);
                //2-修改ydd_user_data表，添加记录
                YddUserData yddUserData = new YddUserData(null,articleId,id,1);
                yddUserDataMapper.insert(yddUserData);
            } else if ("del".equals(action)){//删除
                //1-修改ydd_article表
                yddArticle.setLovenum(lovenum - 1 + "");
                yddArticleMapper.updateById(yddArticle);
                //2-修改ydd_user_data表，删除记录
                QueryWrapper<YddUserData> qw = new QueryWrapper<>();
                qw.eq("article_id",articleId).eq("type",1);
                yddUserDataMapper.delete(qw);
            }
        } else if (type == 2){ //点赞

            //点赞修改只需要修改ydd_user_data表即可
            if ("add".equals(action)){ //添加
                YddUserData yddUserData = new YddUserData(null,articleId,id,2);
                yddUserDataMapper.insert(yddUserData);
            } else if ("del".equals(action)){//删除
                QueryWrapper<YddUserData> qw = new QueryWrapper<>();
                qw.eq("article_id",articleId).eq("type",2);
                yddUserDataMapper.delete(qw);
            }
        }

        return Result.success();
    }

    /**
     * 发布文章
     * @param yddArticle
     * @return
     */
    @Override
    public Result addArticle(YddArticle yddArticle) {
        //新增文章
        if (yddArticle == null) {
            return Result.error("发布文章失败");
        }
        //字段填充
        yddArticle.setCreateDate(System.currentTimeMillis());
        yddArticle.setUpdateDate(System.currentTimeMillis());
        //用户id
        Integer id = Integer.valueOf(BaseContext.getCurrentId());
        yddArticle.setUserId(id);
        //lovenum
        yddArticle.setLovenum("0");

        yddArticleMapper.insert(yddArticle);
        return Result.success("发布文章成功");
    }

    /**
     * 删除文章
     * @param id
     * @return
     */
    @Override
    public Result delArticle(Integer id) {
        if (id == null) {
            return Result.error("id不存在，删除失败");
        }

        yddArticleMapper.deleteById(id);
        return Result.success("删除成功！");
    }

    /**
     * 修改文章
     * @param  yddArticle
     * @return
     */
    @Override
    public Result editArticle(YddArticle yddArticle) {
        //先查询文章是否存在
        if (yddArticle == null) {
            return Result.error("修改文章失败！");
        }

        //修改文章
        yddArticleMapper.updateById(yddArticle);
        return Result.success("修改文章成功");
    }

    /**
     * 前台登录
     * @param dto
     * @return
     */
    @Override
    public Result frontLogin(YddUserLoginDTO dto) {
        if(dto.getMobile().isEmpty()){
            return Result.error("请输入正确的电话号码");
        }
        if(dto.getPassword().isEmpty()){
            return Result.error("请输入正确的密码");
        }
        QueryWrapper<YddUser> qw = new QueryWrapper<>();
        String password = DigestUtils.md5DigestAsHex(dto.getPassword().getBytes());
        qw.eq("mobile",dto.getMobile());
        qw.eq("password",password);
        YddUser yddUser = yddUserMapper.selectOne(qw);
        if(yddUser==null){
            return Result.error("请输入正确的用户名和密码");
        }
        String token = JwtUtil.getToken(String.valueOf(yddUser.getId()));
        Map map = new HashMap();
        map.put("token",token);
        return Result.success(map);
    }

    /**
     * 用户注册
     * @param regDto
     * @return
     */
    @Override
    public YddUserVO reg(RegDto regDto) {
        YddUserVO yddUserVo = new YddUserVO();
        //判断是否有相同的手机号如果有返回账号已存在
        List<YddUser> yddUsers = yddUserMapper.selectList(null);
        for (YddUser yddUser : yddUsers) {
            if (regDto.getMobile().equals(yddUser.getMobile())){
                throw  new AccountLockedException(MessageConstant.ACCOUNT_EXIT_FOUND);
            } }

        //如果没有就把电话和id存在数据库中
        YddUser user = new YddUser();
        user.setMobile(regDto.getMobile().toString());
        //密码加密转入数据库
        String password = DigestUtils.md5DigestAsHex(regDto.getPassword().getBytes());
        user.setPassword(password);
        yddUserMapper.insertUser(user);
        //获取id创建token并放入返回结果中
        String token = JwtUtil.getToken(user.getId().toString());
        yddUserVo.setToken(token);

        return yddUserVo;


    }
}
